package org.cybzacg.encryption.utils;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * 密钥生成工具类
 * 提供各种加密算法的密钥生成功能
 * 
 * @author encryption team
 * @version 1.0
 */
public class KeyGeneratorUtils {
    
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    
    /**
     * 生成AES密钥
     * 
     * @param keySize 密钥长度（128, 192, 256）
     * @return AES密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateAESKey(int keySize) throws NoSuchAlgorithmException {
        if (!isValidAESKeySize(keySize)) {
            throw new IllegalArgumentException("Invalid AES key size: " + keySize + 
                ". Valid sizes are 128, 192, 256");
        }
        
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(keySize, SECURE_RANDOM);
        return keyGenerator.generateKey();
    }
    
    /**
     * 生成AES密钥（默认256位）
     * 
     * @return AES密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateAESKey() throws NoSuchAlgorithmException {
        return generateAESKey(256);
    }
    
    /**
     * 生成DES密钥
     * 
     * @return DES密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateDESKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
        keyGenerator.init(56, SECURE_RANDOM);
        return keyGenerator.generateKey();
    }
    
    /**
     * 生成3DES密钥
     * 
     * @return 3DES密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateTripleDESKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
        keyGenerator.init(168, SECURE_RANDOM);
        return keyGenerator.generateKey();
    }
    
    /**
     * 生成Blowfish密钥
     * 
     * @param keySize 密钥长度（32-448位）
     * @return Blowfish密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateBlowfishKey(int keySize) throws NoSuchAlgorithmException {
        if (keySize < 32 || keySize > 448 || keySize % 8 != 0) {
            throw new IllegalArgumentException("Invalid Blowfish key size: " + keySize + 
                ". Valid sizes are 32-448 bits, multiple of 8");
        }
        
        KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
        keyGenerator.init(keySize, SECURE_RANDOM);
        return keyGenerator.generateKey();
    }
    
    /**
     * 生成Blowfish密钥（默认128位）
     * 
     * @return Blowfish密钥
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static SecretKey generateBlowfishKey() throws NoSuchAlgorithmException {
        return generateBlowfishKey(128);
    }
    
    /**
     * 生成RSA密钥对
     * 
     * @param keySize 密钥长度（1024, 2048, 4096）
     * @return RSA密钥对
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static KeyPair generateRSAKeyPair(int keySize) throws NoSuchAlgorithmException {
        if (!isValidRSAKeySize(keySize)) {
            throw new IllegalArgumentException("Invalid RSA key size: " + keySize + 
                ". Valid sizes are 1024, 2048, 4096");
        }
        
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(keySize, SECURE_RANDOM);
        return keyPairGenerator.generateKeyPair();
    }
    
    /**
     * 生成RSA密钥对（默认2048位）
     * 
     * @return RSA密钥对
     * @throws NoSuchAlgorithmException 如果算法不支持
     */
    public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
        return generateRSAKeyPair(2048);
    }
    
    /**
     * 生成EC密钥对
     * 
     * @param curveName 椭圆曲线名称（如 "secp256r1", "secp384r1", "secp521r1"）
     * @return EC密钥对
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws NoSuchProviderException 如果提供者不支持
     * @throws InvalidAlgorithmParameterException 如果参数无效
     */
    public static KeyPair generateECKeyPair(String curveName) 
            throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
        keyPairGenerator.initialize(new java.security.spec.ECGenParameterSpec(curveName), SECURE_RANDOM);
        return keyPairGenerator.generateKeyPair();
    }
    
    /**
     * 生成EC密钥对（默认secp256r1）
     * 
     * @return EC密钥对
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws NoSuchProviderException 如果提供者不支持
     * @throws InvalidAlgorithmParameterException 如果参数无效
     */
    public static KeyPair generateECKeyPair() 
            throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        return generateECKeyPair("secp256r1");
    }
    
    /**
     * 生成随机字节数组
     * 
     * @param length 字节数组长度
     * @return 随机字节数组
     */
    public static byte[] generateRandomBytes(int length) {
        if (length <= 0) {
            throw new IllegalArgumentException("Length must be positive");
        }
        
        byte[] bytes = new byte[length];
        SECURE_RANDOM.nextBytes(bytes);
        return bytes;
    }
    
    /**
     * 生成随机字符串
     * 
     * @param length 字符串长度
     * @return 随机字符串
     */
    public static String generateRandomString(int length) {
        if (length <= 0) {
            throw new IllegalArgumentException("Length must be positive");
        }
        
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(SECURE_RANDOM.nextInt(chars.length())));
        }
        
        return sb.toString();
    }
    
    /**
     * 生成随机密码
     * 
     * @param length 密码长度
     * @return 随机密码（包含大小写字母、数字和特殊字符）
     */
    public static String generateRandomPassword(int length) {
        if (length < 8) {
            throw new IllegalArgumentException("Password length must be at least 8");
        }
        
        String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String lower = "abcdefghijklmnopqrstuvwxyz";
        String digits = "0123456789";
        String special = "!@#$%^&*()_+-=[]{}|;:,.<>?";
        String all = upper + lower + digits + special;
        
        StringBuilder sb = new StringBuilder(length);
        
        // 确保至少包含每种类型的字符
        sb.append(upper.charAt(SECURE_RANDOM.nextInt(upper.length())));
        sb.append(lower.charAt(SECURE_RANDOM.nextInt(lower.length())));
        sb.append(digits.charAt(SECURE_RANDOM.nextInt(digits.length())));
        sb.append(special.charAt(SECURE_RANDOM.nextInt(special.length())));
        
        // 填充剩余长度
        for (int i = 4; i < length; i++) {
            sb.append(all.charAt(SECURE_RANDOM.nextInt(all.length())));
        }
        
        // 打乱字符顺序
        char[] chars = sb.toString().toCharArray();
        for (int i = chars.length - 1; i > 0; i--) {
            int j = SECURE_RANDOM.nextInt(i + 1);
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
        
        return new String(chars);
    }
    
    /**
     * 从字节数组创建SecretKey
     * 
     * @param keyBytes 密钥字节
     * @param algorithm 算法名称
     * @return SecretKey
     */
    public static SecretKey createSecretKey(byte[] keyBytes, String algorithm) {
        return new SecretKeySpec(keyBytes, algorithm);
    }
    
    /**
     * 从Base64字符串创建SecretKey
     * 
     * @param base64Key Base64编码的密钥
     * @param algorithm 算法名称
     * @return SecretKey
     */
    public static SecretKey createSecretKeyFromBase64(String base64Key, String algorithm) {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        return createSecretKey(keyBytes, algorithm);
    }
    
    /**
     * 从字节数组创建公钥
     * 
     * @param keyBytes 公钥字节
     * @param algorithm 算法名称
     * @return PublicKey
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws InvalidKeySpecException 如果密钥规范无效
     */
    public static PublicKey createPublicKey(byte[] keyBytes, String algorithm) 
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        return keyFactory.generatePublic(keySpec);
    }
    
    /**
     * 从Base64字符串创建公钥
     * 
     * @param base64Key Base64编码的公钥
     * @param algorithm 算法名称
     * @return PublicKey
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws InvalidKeySpecException 如果密钥规范无效
     */
    public static PublicKey createPublicKeyFromBase64(String base64Key, String algorithm) 
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        return createPublicKey(keyBytes, algorithm);
    }
    
    /**
     * 从字节数组创建私钥
     * 
     * @param keyBytes 私钥字节
     * @param algorithm 算法名称
     * @return PrivateKey
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws InvalidKeySpecException 如果密钥规范无效
     */
    public static PrivateKey createPrivateKey(byte[] keyBytes, String algorithm) 
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        return keyFactory.generatePrivate(keySpec);
    }
    
    /**
     * 从Base64字符串创建私钥
     * 
     * @param base64Key Base64编码的私钥
     * @param algorithm 算法名称
     * @return PrivateKey
     * @throws NoSuchAlgorithmException 如果算法不支持
     * @throws InvalidKeySpecException 如果密钥规范无效
     */
    public static PrivateKey createPrivateKeyFromBase64(String base64Key, String algorithm) 
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        return createPrivateKey(keyBytes, algorithm);
    }
    
    /**
     * 将密钥转换为Base64字符串
     * 
     * @param key 密钥
     * @return Base64编码的密钥字符串
     */
    public static String keyToBase64(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }
    
    /**
     * 验证AES密钥长度是否有效
     * 
     * @param keySize 密钥长度
     * @return true如果有效
     */
    public static boolean isValidAESKeySize(int keySize) {
        return keySize == 128 || keySize == 192 || keySize == 256;
    }
    
    /**
     * 验证RSA密钥长度是否有效
     * 
     * @param keySize 密钥长度
     * @return true如果有效
     */
    public static boolean isValidRSAKeySize(int keySize) {
        return keySize == 1024 || keySize == 2048 || keySize == 4096;
    }
    
    /**
     * 获取支持的密钥算法列表
     * 
     * @return 支持的算法数组
     */
    public static String[] getSupportedKeyAlgorithms() {
        return new String[]{
            "AES", "DES", "DESede", "Blowfish", "RSA", "EC", "DSA", "HmacSHA256", "HmacSHA512"
        };
    }
    
    /**
     * 检查算法是否支持
     * 
     * @param algorithm 算法名称
     * @return true如果支持
     */
    public static boolean isAlgorithmSupported(String algorithm) {
        try {
            KeyGenerator.getInstance(algorithm);
            return true;
        } catch (NoSuchAlgorithmException e) {
            return false;
        }
    }
    
    /**
     * 生成盐值
     * 
     * @param length 盐值长度
     * @return 盐值字节数组
     */
    public static byte[] generateSalt(int length) {
        return generateRandomBytes(length);
    }
    
    /**
     * 生成盐值（默认16字节）
     * 
     * @return 盐值字节数组
     */
    public static byte[] generateSalt() {
        return generateSalt(16);
    }
    
    /**
     * 生成IV（初始化向量）
     * 
     * @param blockSize 块大小
     * @return IV字节数组
     */
    public static byte[] generateIV(int blockSize) {
        return generateRandomBytes(blockSize);
    }
    
    /**
     * 生成IV（默认16字节）
     * 
     * @return IV字节数组
     */
    public static byte[] generateIV() {
        return generateIV(16);
    }
}
